// by diablo
//snowtu 2007 加入c目录以方便自创的实行
#include <login.h>

private mapping wiz_status;
private mapping wiz_sites;

private string *wiz_levels = ({
        "(player)",
        "(elder)",
        "(immortal)",
        "(apprentice)",
        "(wizard)",
        "(arch)",
        "(admin)"
});

private mapping trusted_read = ([/*可以读*/
        "/"     : ({ "(admin)","(arch)","(wizard)","(apprentice)","(immortal)",})
]);
private mapping trusted_write = ([/*可以写*/
        "/"     : ({ "(admin)","(arch)"}),
        "d"     : ({ "(wizard)" }),
        "daemon": ({ "(wizard)",}),
        "doc"   : ({ "(wizard)",}),
        "c"     : ({ "(player)",}),
]);

private mapping exclude_write = ([/*不能写*/
        "adm"   : ({"(arch)","(wizard)","(apprentice)","(immortal)", }),
       "include": ({ "(arch)","(wizard)","(apprentice)","(immortal)", }),
        "std"   : ({ "(arch)","(wizard)","(apprentice)","(immortal)", }),
       "feature": ({ "(arch)","(wizard)","(apprentice)","(immortal)", }),
        "data"  : ({ "(arch)","(wizard)","(apprentice)","(immortal)", }),
        "log"   : ({ "(arch)", "(wizard)","(apprentice)","(immortal)", }),
        "cmds"  : ({ "(arch)","(wizard)","(apprentice)","(immortal)",}),
        "d"     : ({"(apprentice)","(immortal)",}),
        "u"     : ({"(arch)","(wizard)","(apprentice)","(immortal)",}),
]);

private mapping exclude_read = ([/*不能读*/
        "adm"   : ({  "(arch)","(wizard)","(apprentice)","(immortal)",}),
        "data"  : ({ "(wizard)","(apprentice)","(immortal)",}),
       "feature": ({  "(arch)","(wizard)","(apprentice)","(immortal)",}),
      "cmds/adm": ({  "(arch)","(wizard)","(apprentice)","(immortal)",}),
     "cmds/arch": ({  "(wizard)","(apprentice)","(immortal)",}),
      "cmds/wiz": ({  "(immortal)",}),
        "u"     : ({  "(arch)","(wizard)","(apprentice)","(immortal)",}),
       "include": ({  "(arch)","(wizard)","(apprentice)","(immortal)",}),
        "std"   : ({  "(wizard)","(apprentice)","(immortal)",}),
        "log"   : ({  "(arch)","(wizard)","(apprentice)","(immortal)",}),
        "d"     : ({  "(immortal)", }),
]); 

void create()
{
	string *wizlist, wiz_name, wiz_level, wiz_site;
	int i;

	wizlist = explode(read_file(WIZLIST), "\n");
	wiz_status = allocate_mapping(sizeof(wizlist));
	wiz_sites = allocate_mapping(sizeof(wizlist));
	for(i=0; i<sizeof(wizlist); i++) 
        {
        	if( wizlist[i][0]=='#' )   
        		continue;
        	if( sscanf(wizlist[i], "%s %s %s",wiz_name, wiz_level,wiz_site)==3 )  
                {
                	wiz_status[wiz_name] = wiz_level;
                	wiz_sites[wiz_name] = wiz_site;
                }
        	else if( sscanf(wizlist[i], "%s %s", wiz_name, wiz_level)!=2 ) 
                	continue;
        	else    
        	{
                	wiz_status[wiz_name] = wiz_level;
                	wiz_sites[wiz_name] = "";
                }
        }
}

string *query_wizlist() { return keys(wiz_status); }

// This function returns the status of an uid.
string get_status(mixed ob)
{
	string euid;
	if( objectp(ob) ) 
        {
        	euid = geteuid(ob);
        	if( !euid ) euid = getuid(ob);
        }
	else if( stringp(ob) ) 
        	euid = ob;
	if( !mapp(wiz_status) )
        	return "(player)";
	if( !undefinedp(wiz_status[euid]) ) 
        	return wiz_status[euid];
	else if( member_array(euid,wiz_levels)!=-1 ) 
        	return euid;
	else return "(player)";
}

int match_wiz_site(object ob, string site)
{
	string* line,euid;

	euid = ob->query("id");
	if( undefinedp(wiz_sites[euid]) || wiz_sites[euid]=="" )  
        	return 1;
	line = ({});
	line+= ({site});
	if( sizeof(regexp(line,wiz_sites[euid]))==1 )
        	return 1;
	return 0;
}

int get_wiz_level(object ob)
{
	return member_array(get_status(ob), wiz_levels);
}

int set_status(mixed ob, string status)
{
	string uid, *wiz, wizlist;
	int i;
	object temp;

	if( geteuid(previous_object())!=ROOT_UID ) 
        	return 0;
	if( previous_object()!=find_object("/cmds/adm/promote") ) 
        	return 0;
	if( clonep(previous_object()) ) 
        	return 0;
	if( userp(ob) )
        	uid = getuid(ob);
	else if( stringp(ob) )   
        	uid = ob;
	else    return 0;
	temp = previous_object(1);
	if( userp(ob) )
        {
        	if( status=="(admin)" && wizhood(temp)!="(admin)" ) 
	                return 0;
        	if( status=="(arch)" && (wizhood(temp)!="(admin)" 
          	&& wizhood(temp)!="(arch)")) 
                	return 0;
        	if( status=="(wizard)" &&(wizhood(temp)!="(admin)"
          	&& wizhood(temp)!="(arch)" && wizhood(temp)!="(wizard)") ) 
	                return 0;
        }               
	if( status == "(player)" )
        	map_delete(wiz_status, uid);
	else    wiz_status[uid] = status;
	wiz = keys(wiz_status);
	for(wizlist = "", i=0; i<sizeof(wiz); i++)
        	wizlist += wiz[i] + " " + wiz_status[wiz[i]] + "\n";
	rm(WIZLIST);
	write_file(WIZLIST, wizlist);
	log_file( "static/promotion", capitalize(uid)+ " become a " + status + " on " + ctime(time()) + "\n" );
	return 1;
}

string *get_wizlist() { return keys(wiz_status); }

int valid_read(string file, mixed user, string func)
{
	string euid, status, *path, dir;
	int i;
        
	if( !objectp(user) )
        	error("TRUST_D->valid_read: Invalid argument type of user.\n");
//snowtu
	if( sscanf(file, "/c/%*s") && !userp(user) )
        	return 1;
//end   
        
// Let user restore their save file
	if( func=="restore_object" ) 
        {
        	if( sscanf(file, "/data/%*s") 
        	&& ( ( file == (string) user->query_save_file() )
        	  || ( file == (string) user->query_save_file() + ".o" ) ) )
			return 1;
        }
	if( func != "read_file" && func != "file_size" 
  	&& func != "stat" && func != "read_bytes" 
  	&& func != "tail" && func != "ed_start" ) 
        	return 1;
// Get the euid and status of the user.
	if( !euid = geteuid(user) )
        	return 1;
	status = get_status(user);
	if( euid==ROOT_UID ) 
        	return 1;
	if( (file=="/u/"||file=="/u")&&wiz_level(status)>wiz_level("(immortal)") )
	        return 1;
	if( sscanf(file, "/u/" + euid + "/%*s") || file=="/u/"+euid )
        	return 1;
	path = explode(file, "/");
	for(i=sizeof(path)-1; i>=0; i--) 
        {
        	dir = implode(path[0..i], "/");
        	if( undefinedp(exclude_read[dir]) ) 
        		continue;
        	if( member_array(euid, exclude_read[dir])!=-1 ) 
        		return 0;
        	if( member_array(status, exclude_read[dir])!=-1 ) 
        		return 0;
        }
	return 1;
}

int valid_write(string file, mixed user, string func)
{
	string euid, status, *path, dir;
	int i;

	if( !objectp(user) )
        	error("TRUST_D->valid_write: Invalid argument type of user.\n");
//snowtu
	if( sscanf(file, "/c/%*s") && !userp(user) )
        	return 1;
        if( base_name(user)=="/obj/armor" || base_name(user)=="/obj/weapon" || inherits("/obj/fabao",user) || base_name(user)=="/obj/fabao" )
        	return 1;	
//end   
	if( valid_read(file,user,func)==0 ) 
        	return 0;  
	if( sscanf(file, LOG_DIR + "%*s") && func=="write_file" ) 
        	return 1;
	if( func=="save_object" ) 
        {
        	if( ( sscanf(base_name(user), "/obj/%*s") 
            	|| sscanf(base_name(user), "/d/%*s") 
            	|| sscanf(base_name(user), "/u/tool/obj/%*s") )
          	&& sscanf(file, "/data/%*s")
          	&& ( file==(string)user->query_save_file() 
            	|| file == (string)user->query_save_file()+".o" 
            	|| file == (string)user->query_save_file()+".oo.o" 
            	|| file == ((string)user->query_save_file()+".oo") ) )
	                return 1;
        }
// Get the euid and status of the user.
	euid = geteuid(user);
	if( !euid ) return 0;
	status = get_status(user);
	if( euid==ROOT_UID ) return 1;
	if( sscanf(file, "/u/" + euid + "/%*s") ) 
        {
        	log_file("files", sprintf("[%s] %s(%s) %ss %s.\n",ctime(time()),euid,status,func,file));
        	return 1; 
        }
	path = explode(file, "/");
// Check if we are excluded in one of the directories containing the file.
	for (i=sizeof(path)-1; i>=0; i--) 
        {
        	dir = implode(path[0..i], "/");
        	if( undefinedp(exclude_write[dir]) ) continue;
        	if( member_array(euid, exclude_write[dir])!=-1 ) return 0;
        	if( member_array(status, exclude_write[dir])!=-1 ) return 0;
        }
// And then check if we are trusted in one of the directories containing the file.
	if( member_array(euid, trusted_write["/"])!=-1 ) 
        {
        	if( func == "ls" ) return 1;
	        log_file("files", sprintf("[%s] %s(%s) %ss %s.\n",ctime(time()),euid,status,func,file));
        	return 1;
        }
	if( member_array(status, trusted_write["/"])!=-1 )
        {
        	if(func == "ls" ) return 1;
        	log_file("files", sprintf("[%s] %s(%s) %ss %s.\n",ctime(time()),euid,status,func,file));
        	return 1;
        }
	if( path[0] == "u") return 0;
	for(i=sizeof(path)-1; i>=0; i--) 
        {
        	dir = implode(path[0..i], "/");
        	if( undefinedp(trusted_write[dir]) ) continue;
        	if( member_array(euid, trusted_write[dir])!=-1 )
                {
	                if( func == "ls" ) return 1;
        	        log_file("files", sprintf("[%s] %s(%s) %ss %s.\n",ctime(time()),euid,status,func,file));
                	return 1;
                }
        	if( member_array(status, trusted_write[dir])!=-1 )
                {
                	if( func == "ls" ) return 1;
                	log_file("files", sprintf("[%s] %s(%s) %ss %s.\n",ctime(time()),euid,status,func,file));
                	return 1;
                }
        }
	log_file("files", sprintf("[%s] %s(%s) write attempt on %s failed.\n",ctime(time()),euid, status, file));
	return 0;
}

int valid_seteuid( object ob, string uid )
{
	if( uid==0 ) return 1;
	if( uid==getuid(ob) ) return 1;
	if( getuid(ob)==ROOT_UID ) return 1;
	if( sscanf(file_name(ob), "/adm/%*s") ) return 1;
	if( wiz_status[uid] != "(admin)" && wiz_status[getuid(ob)] == "(admin)" )
        	return 1;
	return 0;
}
